(function (window, angular) {
    'use strict';
    angular.module("Directive.Validation", [])
        .directive("ybSerialNo", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /^[a-zA-Z0-9]+$/;
                    if (!angular.isDefined(ctrl.$error.serialNo)) {
                        ctrl.$error.serialNo = false;
                    }
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("serialNo", false);
                            } else {
                                ctrl.$setValidity("serialNo", true);
                            }
                        })
                    });

                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("serialNo", true);
                        } else {
                            if (!pattern.test(value)) {
                                ctrl.$setValidity("serialNo", false);
                            } else {
                                ctrl.$setValidity("serialNo", true);
                            }
                        }
                        return value;
                    })
                }
            };
        })

        .directive("ybMobile", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /^1\d{10}$/;
                    if (!angular.isDefined(ctrl.$error.mobile)) {
                        ctrl.$error.mobile = false;
                    }
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("mobile", false);
                            } else {
                                ctrl.$setValidity("mobile", true);
                            }
                        })
                    });

                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("mobile", true);
                        } else {
                            if (!pattern.test(value)) {
                                ctrl.$setValidity("mobile", false);
                            } else {
                                ctrl.$setValidity("mobile", true);
                            }
                        }
                        return value;
                    })
                }
            };
        })

        .directive("ybTel", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /^(0\d{2,3}-?)?\d{7,8}$/;
                    ctrl.$setValidity("tel", true);
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("tel", false);
                            } else {
                                ctrl.$setValidity("tel", true);
                            }
                        })
                    });

                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("tel", true);
                        } else {
                            if (!pattern.test(value) && value != "") {
                                ctrl.$setValidity("tel", false);
                            } else {
                                ctrl.$setValidity("tel", true);
                            }
                        }
                        return value;
                    })
                }
            };
        })

        .directive("ybContact", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var telPattern = /^1\d{10}$/;
                    var mobilePattern = /^(0\d{2,3}-?)?\d{7,8}$/;
                    if (!angular.isDefined(ctrl.$error.mobile)) {
                        ctrl.$error.mobile = false;
                    }
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !telPattern.test(ctrl.$modelValue) && !mobilePattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("contactInfo", false);
                            } else {
                                ctrl.$setValidity("contactInfo", true);
                            }
                        })
                    });

                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("contactInfo", true);
                        } else {
                            if (!telPattern.test(ctrl.$modelValue) && !mobilePattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("contactInfo", false);
                            } else {
                                ctrl.$setValidity("contactInfo", true);
                            }
                        }
                        return value;
                    })
                }
            };
        })

        .directive("ybPureNum", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /^\d+$/;

                    ctrl.$setValidity("pureNum", true);
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("pureNum", false);
                            } else {
                                ctrl.$setValidity("pureNum", true);
                            }
                        })
                    });

                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("pureNum", true);
                        } else {
                            if (pattern.test(value)) {
                                ctrl.$setValidity("pureNum", false);
                            } else {
                                ctrl.$setValidity("pureNum", true);
                            }
                        }
                        return value;
                    })
                }
            };
        })

        .directive("ybPassword", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /^[^\s]{6,20}$/;
                    if (!angular.isDefined(ctrl.$error.pass)) {
                        ctrl.$error.pass = false;
                    }
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("password", false);
                            } else {
                                ctrl.$setValidity("password", true);
                            }
                        })
                    });

                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("password", true);
                        } else {
                            if (!pattern.test(value)) {
                                ctrl.$setValidity("password", false);
                            } else {
                                ctrl.$setValidity("password", true);
                            }
                        }
                        return value;
                    })
                }
            };
        })

        .directive("ybEmail", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;
                    ctrl.$setValidity("email", true);
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("email", false);
                            } else {
                                ctrl.$setValidity("email", true);
                            }
                        });
                    });
                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("email", true);
                        } else {
                            if (!pattern.test(value) && value != "") {
                                ctrl.$setValidity("email", false);
                            } else {
                                ctrl.$setValidity("email", true);
                            }
                        }
                        return value;
                    })
                }
            }
        })

        .directive("ybUrl", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_#-](\?)?)*)*$/i;
                    ctrl.$error.url = false;
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("url", false);
                            } else {
                                ctrl.$setValidity("url", true);
                            }
                        })
                    });
                }
            };
        })

        .directive("ybIdNo", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    ctrl.$error.idNo = false;
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !validateIdNo(ctrl.$modelValue)) {
                                ctrl.$setValidity("idNo", false);
                            } else {
                                ctrl.$setValidity("idNo", true);
                            }
                        })
                    });
                    // 验证身份证号码
                    function validateIdNo(idCard) {
                        var Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
                        var ValideCode = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2];
                        idCard = trim(idCard.replace(/ /g, ""));//去掉字符串头尾空格

                        if (idCard.length == 15) {
                            //进行15位身份证的验证
                            return isValidityBrithBy15IdCard(idCard);
                        } else if (idCard.length == 18) {
                            var idCard_arr = idCard.split("");// 得到身份证数组

                            /**
                             * 进行18位身份证的基本验证和第18位的验证
                             */
                            return (isValidityBrithBy18IdCard(idCard) && isTrueValidateCodeBy18IdCard(idCard_arr));
                        } else {
                            return false;
                        }

                        function isTrueValidateCodeBy18IdCard(a_idCard) {
                            var sum = 0;// 声明加权求和变量
                            if (a_idCard[17].toLowerCase() == 'x') {
                                a_idCard[17] = 10;// 将最后位为x的验证码替换为10方便后续操作
                            }
                            for (var i = 0; i < 17; i++) {
                                sum += Wi[i] * a_idCard[i];// 加权求和
                            }
                            var valCodePosition = sum % 11;// 得到验证码所位置
                            return (a_idCard[17] == ValideCode[valCodePosition]);
                        }

                        function isValidityBrithBy18IdCard(idCard18) {
                            var year = idCard18.substring(6, 10);
                            var month = idCard18.substring(10, 12);
                            var day = idCard18.substring(12, 14);
                            var temp_date = new Date(year, parseFloat(month) - 1, parseFloat(day));
                            // 这里用getFullYear()获取年份，避免千年虫问题
                            return !(temp_date.getFullYear() != parseFloat(year) || temp_date.getMonth() != parseFloat(month) - 1 || temp_date.getDate() != parseFloat(day));
                        }

                        function isValidityBrithBy15IdCard(idCard15) {
                            var pattern = /^\d{15}$/;
                            return pattern.test(idCard15);
                        }

                        //去掉字符串头尾空格
                        function trim(str) {
                            return str.replace(/(^\s*)|(\s*$)/g, "");
                        }
                    }
                }
            };
        })

        .directive("ybZipCode", function () {
            return {
                restrict: "A",
                require: "?ngModel",
                link: function (scope, element, attrs, ctrl) {
                    if (!ctrl) {
                        return;
                    }
                    var pattern = /^\d{6}$/;
                    ctrl.$error.postcode = false;
                    element.on("blur", function (event) {
                        scope.$apply(function () {
                            if (!!ctrl.$modelValue && !pattern.test(ctrl.$modelValue)) {
                                ctrl.$setValidity("postcode", false);
                            } else {
                                ctrl.$setValidity("postcode", true);
                            }
                        })
                    });

                    ctrl.$formatters.unshift(function (value) {
                        if (!value) {
                            ctrl.$setValidity("postcode", true);
                        } else {
                            if (!pattern.test(value) && value != "") {
                                ctrl.$setValidity("postcode", false);
                            } else {
                                ctrl.$setValidity("postcode", true);
                            }
                        }
                        return value;
                    })
                }
            };
        })
        
        .directive("ybNumberInput", [function () {
            return {
                restrict: "A",
                require: "?ngModel",
                scope: {
                    start: "=?start",
                    min: "=?min",
                    max: "=?max",
                    disableDecimal: "=?disableDecimal",
                    decimalPlaces: "=?decimalPlaces",
                    allowNulls: "=?"
                },
                link: function (scope, element, attrs, ctrl) {
                    var ngModelCtrl = ctrl;
                    if (!ngModelCtrl) {
                        return;
                    }
                    if (!angular.isDefined(scope.disableDecimal)) {
                        scope.disableDecimal = true;
                    }
                    if (!angular.isDefined(scope.decimalPlaces)) {
                        scope.decimalPlaces = 0;
                    }
                    ngModelCtrl.$parsers.push(function (value) {
                        if (angular.isUndefined(value) && !value) {
                            return value;
                        }
                        if (angular.isNumber(value)) {
                            return value;
                        }
                        var isChanged = false;
                        var regExp = /^\d+\.?\d*$/;
                        if (scope.disableDecimal) {
                            regExp = /^\d+$/;
                        }
                        var valueStr = value.toString();
                        for (var i = valueStr.length; i > 0; i--) {
                            if (!regExp.test(valueStr.substring(0, i))) {
                                valueStr = valueStr.substring(0, i - 1);
                                isChanged = true;
                            } else {
                                break;
                            }
                        }
                        if (valueStr.length == 2) {
                            if (valueStr[0] == "0" && valueStr[1] != ".") {
                                valueStr = valueStr.substring(1, 2);
                                isChanged = true;
                            }
                        }
                        if (!scope.disableDecimal) {
                            if (angular.isUndefined(scope.decimalPlaces)) {
                                scope.decimalPlaces = 2;
                            }
                            var demicalIndex = valueStr.indexOf(".");
                            if ((demicalIndex > -1) && (valueStr.length > demicalIndex + scope.decimalPlaces + 1)) {
                                valueStr = valueStr.substring(0, demicalIndex + scope.decimalPlaces + 1);
                                isChanged = true;
                            }
                        }
                        if (isChanged) {
                            renderView(valueStr);
                        }
                        compareMaxAndMinValue(valueStr);
                        return valueStr;
                    });

                    function translateStringToNumber(value) {
                        if (value == "") {
                            return scope.min;
                        }
                        return +parseFloat(value).toFixed(scope.decimalPlaces);
                    }

                    function compareMaxAndMinValue(value) {
                        if (value == "") {
                            return;
                        }
                        var numberValue = translateStringToNumber(value);
                        var isChanged = false;
                        if (numberValue > scope.max) {
                            value = scope.max;
                            isChanged = true;
                        }
                        if (isChanged) {
                            renderView(value);
                        }
                    }

                    function renderView(value) {
                        ngModelCtrl.$setViewValue(value);
                        ngModelCtrl.$render();
                    }
                }
            }
        }])
    ;
})(window, window.angular);